package com.xxg.fileshand.base

import android.text.TextUtils
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModel
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.viewModelScope
import androidx.viewbinding.ViewBinding
import com.blankj.utilcode.util.ToastUtils
import com.xxg.fileshand.net.NetWorkException
import com.xxg.fileshand.net.RetrofitManager
import kotlinx.coroutines.*
import org.json.JSONException
import retrofit2.HttpException
import java.io.IOException
import java.net.ConnectException
import java.net.SocketTimeoutException
import java.net.UnknownHostException
import java.text.ParseException

/**
 * 对ViewModel的一个协程拓展函数
 */
fun ViewModel.launch(
    block: suspend CoroutineScope.() -> Unit,
    onError: (e: Throwable) -> Unit = {},
    onComplete: () -> Unit = {}
) {
    viewModelScope.launch(CoroutineExceptionHandler { _, e -> onError(e) }) {
        try {
            block.invoke(this)
        } finally {
            onComplete.invoke()
        }
    }

}

fun ViewModel.async(
    block: suspend CoroutineScope.() -> Unit,
    onError: (e: Throwable) -> Unit = {},
    onComplete: () -> Unit = {}
) {
    viewModelScope.async(CoroutineExceptionHandler { _, e -> onError(e) }) {
        try {
            block.invoke(this)
        } finally {
            onComplete.invoke()
        }
    }

}

fun ViewModel.showException(e: Throwable) {
    var code = 0
    var errorMsg = e.message
    if (e is Exception) {
        if (e is IOException) {

            //errorMsg = "Please check your network status"
        } else if (e is HttpException) {
            /** 网络异常，http 请求失败，即 http 状态码不在 [200, 300) 之间, such as: "server internal error".  */
//            errorMsg = ((HttpException) e).response().message();
            e.response()?.apply {
                code = code()
                if (errorBody() != null) {
                    errorMsg = errorBody()!!.string()
                }
            }


        } else if (e is NetWorkException) {
            code = e.code
            errorMsg = e.message
        } else {
            /** 其他未知错误  */
            errorMsg = if (!TextUtils.isEmpty(e.message)) e.message else "unknown error"
        }
        if (errorMsg == "") {
            errorMsg = e.message
        }
        e.printStackTrace()
    }

}

/**
 * 对AppCompatActivity的一个协程拓展函数
 */
fun AppCompatActivity.launch(
    block: suspend CoroutineScope.() -> Unit,
    onError: (e: Throwable) -> Unit = {},
    onComplete: () -> Unit = {}
) {
    lifecycleScope.launch(CoroutineExceptionHandler { _, e -> onError(e) }) {
        try {
            block.invoke(this)
        } catch (e: Exception) {
            filterException(e, onError)
            e.printStackTrace()
        } finally {
            onComplete.invoke()
        }
    }

}

fun <T> createApi(cls: Class<T>): T {
    return RetrofitManager.build().create(cls)
}

fun <T> filterException(e: Exception, error: (e: Exception) -> T) {
    if (e is CancellationException) {
        return
    }
    val errorMsg: String
    when (e) {
        is NetWorkException -> {//接口通信正常 自定义错误
            errorMsg = e.message ?: ("" + " , code:" + e.code)
            error(NetWorkException(errorMsg))
        }
        is UnknownHostException -> {
            errorMsg = "连接服务器失败,未知host"
            error(Exception(errorMsg))
        }

        is ConnectException -> {
            errorMsg = "连接服务器失败，请检查网络是否可用"
            error(Exception(errorMsg))
        }

        is SocketTimeoutException -> {
            errorMsg = "请求网络超时,请稍后再试"
            error(Exception(errorMsg))
        }

        is ParseException -> {
            errorMsg = "数据解析错误"
            error(Exception(errorMsg))
        }

        is JSONException -> {
            errorMsg = "数据解析错误"
            error(Exception(errorMsg))
        }

        is HttpException -> {
            errorMsg = convertStatusCode(e)
            error(Exception(errorMsg))
        }

        is IOException -> {
            errorMsg = e.message ?: ""
            error(e)
        }

        else -> {
            errorMsg = e.message ?: ""
            error(e)
        }
    }
    if (e !is NetWorkException) {
        ToastUtils.showShort(errorMsg)
    }
}

private fun convertStatusCode(httpException: HttpException): String {
    val msg: String = when {
        httpException.code() in 500..599 -> {
            "服务器处理请求出错:${httpException.code()}"
        }

        httpException.code() in 400..499 -> {
            "服务器无法处理请求:${httpException.code()}"
        }

        httpException.code() in 300..399 -> {
            "请求被重定向到其他页面:${httpException.code()}"
        }

        else -> {
            httpException.message() + ":" + httpException.code()
        }
    }
    return msg
}

/**
 * 对AppCompatActivity的一个协程拓展函数
 */
fun Fragment.launch(
    block: suspend CoroutineScope.() -> Unit,
    onError: (e: Throwable) -> Unit = {},
    onComplete: () -> Unit = {}
) {
    viewLifecycleOwner.lifecycleScope.launch(CoroutineExceptionHandler { _, e -> onError(e) }) {
        try {
            block.invoke(this)
        } finally {
            onComplete.invoke()
        }
    }

}

fun BaseVMFragment<out ViewBinding, out BaseViewModel>.showException(
    e: Throwable
) {


    var code = 0
    var errorMsg = e.message
    if (e is Exception) {
        if (e is IOException) {
            /** 没有网络  */

            //errorMsg = "Please check your network status"
        } else if (e is HttpException) {
            /** 网络异常，http 请求失败，即 http 状态码不在 [200, 300) 之间, such as: "server internal error".  */
//            errorMsg = ((HttpException) e).response().message();
            e.response()?.apply {
                code = code()
                if (errorBody() != null) {
                    errorMsg = errorBody()!!.string()
                }
            }


        } else if (e is NetWorkException) {
            code = e.code
            errorMsg = e.message
        } else {
            /** 其他未知错误  */
            errorMsg = if (!TextUtils.isEmpty(e.message)) e.message else "unknown error"
        }
//        Timber.e("error:%s", errorMsg)
        if (errorMsg == "") {
            errorMsg = e.message
        }
//        loadFailure(code, errorMsg!!)
        e.printStackTrace()
    }

}

fun Fragment.async(
    block: suspend CoroutineScope.() -> Unit,
    onError: (e: Throwable) -> Unit = {},
    onComplete: () -> Unit = {}
) {
    //在fragment中使用viewLifecycleOwner https://mp.weixin.qq.com/s/_2YSV_JsjDJ7CuHJngMbqQ
    viewLifecycleOwner.lifecycleScope.async(CoroutineExceptionHandler { _, e -> onError(e) }) {
        try {
            block.invoke(this)
        } finally {
            onComplete
        }
    }

}